<?php
    /*
        WGET class, post by hs <powerpolly@gmail.com>
        
    */
    //  GET /question/1307030207163.html HTTP/1.1
    //  Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/x-shockwave-flash, application/vnd.ms-powerpoint, application/vnd.ms-excel, application/msword, */*
    //  Accept-Language: zh-cn
    //  Accept-Encoding: gzip, deflate
    //  User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1)
    //  Host: ks.cn.yahoo.com
    //  Connection: Keep-Alive
    //  Cookie: ebNewBandWidth_.cn.yahoo.com=2051%3A1170419845294; ebBurstingTime_.cn.yahoo.com=1170419845424; ebNewHistory_.cn.yahoo.com=193984%3A1170419845424%3A1%3A1170419845434%3A1; CN_FP_TAB=todaytabs%3Dtodaytabscon%2C%2Copen%2Cend%7Cschtabs%3Dschtabscon%2C%2Copen%2Cend%7Ccdntabs%3Dcdntabscon%2C%2Copen%2Cend; B=8obacft2p7oa4&b=3&s=3h; F=a=Rthad9IsvfugDBW0.4bq.s1.reWNvZSmPfUAP898.Y_OhuaFXaIYU.2DoC5l&b=CoCl; YLS=v=1&p=0&n=0; Q=q1=AACAAAAAAAAAAA--&q2=Rb9EOg--; C=mg=1
    //  ...
    
    class WGet
    {
        
        var $_debug = 0;
        
        var $fp;
        var $timeOut = 10;
        var $error;
        
        var $url;
        var $port;
        
        var $inCharset;
        var $outCharset;
        var $charset;
        
        var $postHead;
        var $head;
        var $body;
        var $_prop;
        
        public function __construct()
        {
            $this->fp = 0;
            $this->error = null;
            $this->url = null;
            $this->postHead = array();
            $this->head = $this->body = "";
            $this->_prop = array( "cookie"=>array());
            $this->charset = array( 'auto', 'gb2312', 'utf-8', 'utf-16', 'UCS-2', 'iso-8859-1' );
            
            $this->setInCharset( "gb2312" );
            $this->setOutCharset( "gb2312" );
        }
        
        private function connect( $url, $port = 0, $timeOut = 0 )
        {
            if( !$parts = parse_url( $url ))
                return false;
            if( !$port ) {
                $port = $this->port;
            }
            if( !$timeOut ) {
                $timeOut = $this->timeOut;
            }
            if( !$this->fp = fsockopen( $parts['host'], $port, $errno, $errstr, $timeOut )) {
                echo "连接主机 ".$parts['host']." 失败！";
            }
            // verify we connected properly
            if( empty( $this->fp )) {
                $this->error = array("error" => "Failed to connect to server",
                                     "errno" => $errno,
                                     "errstr" => $errstr);
                return false;
            }
            if( $this->_debug >= 3 ) {
                $this->fp = fopen( "header.txt", "w" );
            }
            return true;
        }
        
        public function fetchContent( $fetch_page_method, $url, $port = 80, $method = "GET", $referer = "", $cookie = "", $post = "" )
        {
            if( $fetch_page_method == "get_file" ) {
                $flag = $this->fetchByReadFile( $url );
            }
            elseif( $fetch_page_method == "use_socket" ) {
                $flag = $this->fetchBySocket( $url, $port, $method, $referer, $cookie, $post );
            }
            else {
                return false;
            }
            if( $this->inCharset == "auto" ) {
                preg_match( "`<meta.*charset\s*=(.+)['\"].*>`Uim", $this->body, $match );
                $currentCharset = strtolower( trim( $match[1] ));
            }
            else {
                $currentCharset = $this->inCharset;
            }
            if( in_array( $currentCharset, $this->charset ) && $currentCharset != $this->outCharset ) {
                $this->body = mb_convert_encoding( $this->body, $this->outCharset, $currentCharset );
            }
            return $flag;
        }
        
        private function fetchByReadFile( $url ) {
            if( !$this->body = file_get_contents( $url )) {
                return false;
            }
            return true;
        }
        
        // The method must be uppercase instead of lowercase, or it will can't transfer the post data  !!!
        private function fetchBySocket( $url, $port = 80, $method = "GET", $referer = "", $cookie = "", $post = "", $listUrl = "" )
        {
            $this->head = $this->body = "";
            $this->postHead = array();
            $parts = parse_url( $url );
            if( !$this->isConnected()) {
                if( !$this->connect( $url, $port )) {
                    $this->error = array(
                        "error" => "Called fetch() without being connected");
                    return false;
                }
            }
            $path = $parts['query'] ? $parts['path']."?".$parts['query'] : $parts['path'];
            array_push( $this->postHead, $method." $path HTTP/1.1\n" );
            array_push( $this->postHead, "Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/x-shockwave-flash, application/vnd.ms-powerpoint, application/vnd.ms-excel, application/msword, */*\n" );
            if( $referer ) {
                if( $referer == "homepage" ) {
                    $referer = $parts['scheme']."://".$parts['host'];
                }
                elseif( $referer == "listpage" ) {
                    $referer = $listUrl;
                }
                array_push( $this->postHead, "Referer: ".$referer."\n" );
            }
            array_push( $this->postHead, "Accept-Language: zh-cn\n" );
            //array_push( $this->postHead, "Accept-Encoding:gzip, deflate\n" );
            array_push( $this->postHead, "User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1)\n" );
            // 注意：如果这里用 Keep-Alive 将不能读娶某些网站例如163.com
            array_push( $this->postHead, "Host: ".$parts['host']."\n" );
            array_push( $this->postHead, "Connection: Close\n" );   //Keep-Alive
            //array_push( $this->postHead, "PRAGMA:no-cache\n" );
            
            if( !empty( $cookie )) {
                array_push( $this->postHead, "cookie: $cookie\n" );
            }
            if( $method == "POST" ) {
                array_push( $this->postHead, "Content-Type: application/x-www-form-urlencoded\n" );
                array_push( $this->postHead, "Content-length: ".strlen( $post ));   // require
            }
            array_push( $this->postHead, "\n\n" );
            
            if( !empty( $post )) {
                array_push( $this->postHead, $post );
            }
            foreach( $this->postHead as $k => $v ) {
                fputs( $this->fp, $v );
            }
            
            while( !feof( $this->fp )) {
                $line = fgets( $this->fp, 8092 );
                $this->head .= $line;
                if( $line == "\r\n" )
                    break;
            }
            $this->parseHeader();
            if( $this->getHeader( "status" ) != 200 && $this->_debug < 3 ) {
                $this->error = array( "error" => "the page ‘".$parts['host'].$parts['path']."’ can't be found !");
                $this->body = "";
                $this->close();
                return false;
            }
            // 再取内容。。。
            while( !feof( $this->fp )) {
                $line = fgets( $this->fp, 10240 );
                $this->body .= $line;
            }

            $this->close();
            return true;
        }
        
        private function parseHeader()
        {
            $arr = explode( "\n", $this->head );
            array_pop( $arr );array_pop( $arr );
            $statusLine = array_shift( $arr );
            preg_match( "@http/1\.\d+\s(\d{3})\s\w+@i", $statusLine, $matches );
            $this->setHeader( "status", $matches[1] );
            foreach( $arr as $k => $v ) {
                $tmp = explode( ":", $v );
                if( !stristr( $tmp[0], "cookie" )) {
                    $this->setHeader( trim( $tmp[0] ), trim( $tmp[1] ));
                }
                else {
                    $tmp = explode( ";", $tmp[1] );
                    foreach( $tmp as $kk => $vv ) {
                        $tmp2 = explode( "=", $vv );
                        $this->setHeader( trim( $tmp2[0] ), trim( $tmp2[1] ), true );
                    }
                }
            }
            return true;
        }
        
        public function setHeader( $key, $value, $isCookie = false )
        {
            if( $isCookie ) {
                $this->_prop['cookie'][$key] = $value;
            }
            else {
                $this->_prop[$key] = $value;
            }
        }
        
        public function getHeader( $key, $defaultValue = null )
        {
            $value = $this->_prop[$key];
            if( $value == "" || $value == null )
                if( $defaulValue != null )
                    $value = $defaultValue;
           
            return $value;
        }
        
        public function getBody()
        {
            return $this->body;
        }
        
        public function getHeaderAsArray()
        {
            return $this->_prop;
        }
        
        public function getHeaderAsString()
        {
            return $this->head;
        }
        
        public function getErrorAsArray()
        {
            return $this->error;
        }
        
        public function getPostHeadAsArray()
        {
            return $this->postHead;
        }

        private function isConnected()
        {
            if( !empty( $this->fp )) {
                //$sock_status = socket_get_status($this->fp);
                //if($sock_status["eof"])
                if( feof( $this->fp )) {
                    $this->Close();
                }
                return true;    // everything looks good
            }
            return false;
        }
        
        public function close()
        {
            $this->error = null;    // so there is no confusion
            $this->url = null;
            if( !empty( $this->fp )) {
                // close the connection and cleanup
                fclose( $this->fp );
                $this->fp = null;
            }
        }
        
        public function setInCharset( $charset )
        {
            if( in_array( $charset, $this->charset ))
                $this->inCharset = $charset;
            else
                $this->inCharset = "gb2312";
        }
        
        public function setOutCharset( $charset )
        {
            if( in_array( $charset, $this->charset ))
                $this->outCharset = $charset;
            else
                $this->outCharset = "gb2312";
        }
        
    }
?>